/*
 * FindBugs - Find Bugs in Java programs
 * Copyright (C) 2008 David H. Hovemeyer <david.hovemeyer@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs.gui2;

import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.ListModel;
import javax.swing.filechooser.FileFilter;

import edu.umd.cs.findbugs.DiscoverSourceDirectories;
import edu.umd.cs.findbugs.Project;
import edu.umd.cs.findbugs.ba.ClassNotFoundExceptionParser;
import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
import edu.umd.cs.findbugs.classfile.ClassDescriptor;
import edu.umd.cs.findbugs.classfile.IErrorLogger;
import edu.umd.cs.findbugs.classfile.MethodDescriptor;

/**
 * Wizard dialog to automatically find and configure
 * source directories for a project.
 * 
 * @author David Hovemeyer
 */
public class SourceDirectoryWizard extends javax.swing.JDialog {
    
    private static final int MIN_STEP = 1;
    private static final int MAX_STEP = 2;
    
    /** Creates new form SourceDirectoryWizard 
     * @param parentGUI */
    public SourceDirectoryWizard(java.awt.Frame parent, boolean modal, Project project, NewProjectWizard parentGUI) {
        super(parent, modal);
        this.parentGUI = parentGUI;
        this.project = project;
        initComponents();
        setStep(1);
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    
        // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
        private void initComponents() {

    	  		foundModel = new DefaultListModel();
    	  		progressModel = new DefaultListModel();
                contentPanel = new javax.swing.JPanel();
                secondPanel = new javax.swing.JPanel();
                jScrollPane1 = new javax.swing.JScrollPane();
                jScrollPane2 = new javax.swing.JScrollPane();
                jList1 = new javax.swing.JList();
                jList2 = new javax.swing.JList();
                jLabel1 = new javax.swing.JLabel();
                jLabel2 = new javax.swing.JLabel();
                jLabel3 = new javax.swing.JLabel();
                firstPanel = new javax.swing.JPanel();
                sourceRootLabel = new javax.swing.JLabel();
                sourceRootBox = new javax.swing.JTextField();
                srcFileIconLabel = new javax.swing.JLabel();
                card1TitleLabel = new javax.swing.JLabel();
                chooser = new JFileChooser();
                browseButton = new javax.swing.JButton();
                card1Explanation1Label = new javax.swing.JLabel();
                card1Explanation2Label = new javax.swing.JLabel();
                card1Explanation3Label = new javax.swing.JLabel();
                previousButton = new javax.swing.JButton();
                nextButton = new javax.swing.JButton();
                finshButton = new javax.swing.JButton();
                errorMessageLabel = new javax.swing.JLabel();
                Dimension d= new Dimension(600,425);
                this.setPreferredSize(d);
                setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
                setTitle("FindBugs Source Directory Configuration Wizard");
                getContentPane().setLayout(null);
                
                jList2.setModel(progressModel);
                
                contentPanel.setLayout(new java.awt.CardLayout());

                secondPanel.setLayout(null);

                jScrollPane1.setViewportView(jList1);

                secondPanel.add(jScrollPane1);
                jScrollPane1.setBounds(250, 50, 258, 130);

                jLabel1.setFont(new java.awt.Font("SansSerif", 0, 14));
                jLabel1.setText("Source directories found:");
                secondPanel.add(jLabel1);
                jLabel1.setBounds(250, 30, 173, 17);

                jLabel2.setFont(new java.awt.Font("SansSerif", 0, 14));
                jLabel2.setText("Click Finish to accept this");
                secondPanel.add(jLabel2);
                jLabel2.setBounds(40, 90, 173, 17);

                jLabel3.setFont(new java.awt.Font("SansSerif", 0, 14));
                jLabel3.setText("list of source directories");
                secondPanel.add(jLabel3);
                jLabel3.setBounds(40, 110, 165, 17);

                contentPanel.add(secondPanel, "card2");

                jScrollPane2.setViewportView(jList2);

                firstPanel.add(jScrollPane2);
                jScrollPane2.setBounds(200, 250, 250, 75);
                
                firstPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
                firstPanel.setLayout(null);

                sourceRootLabel.setText("Top-level source directory:");
                firstPanel.add(sourceRootLabel);
                sourceRootLabel.setBounds(30, 220, 168, 17);
                firstPanel.add(sourceRootBox);
                sourceRootBox.setBounds(200, 210, 250, 29);

                srcFileIconLabel.setIcon(new javax.swing.ImageIcon("/usr/share/icons/default.kde/128x128/mimetypes/source_java.png")); // NOI18N
                firstPanel.add(srcFileIconLabel);
                srcFileIconLabel.setBounds(50, 80, 128, 128);

                card1TitleLabel.setFont(new java.awt.Font("Dialog", 1, 24));
                card1TitleLabel.setText("Where are your source files?");
                firstPanel.add(card1TitleLabel);
                card1TitleLabel.setBounds(150, 20, 353, 29);

                browseButton.setText("Browse...");
                firstPanel.add(browseButton);
                
                browseButton.addActionListener(new ActionListener()
        		{
        			public void actionPerformed(ActionEvent evt)
        			{
        				chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        				chooser.setMultiSelectionEnabled(true);
        				chooser.setApproveButtonText("Choose");
        				chooser.setDialogTitle("Choose the directory");   			
        			        				
        				if (chooser.showOpenDialog(SourceDirectoryWizard.this) == JFileChooser.APPROVE_OPTION)
        				{
        					File[] selectedFiles = chooser.getSelectedFiles();
        					for(File selectedFile : selectedFiles)
        					{
        						sourceRootBox.setText(selectedFile.getAbsolutePath());
        					}
        					nextButton.setEnabled(!sourceRootBox.getText().equals(""));
        				}
        			}
        		});
                
                browseButton.setBounds(450, 210, 100, 28);

                card1Explanation1Label.setFont(new java.awt.Font("SansSerif", 0, 14));
                card1Explanation1Label.setText("Enter the top-level directory");
                firstPanel.add(card1Explanation1Label);
                card1Explanation1Label.setBounds(230, 80, 193, 17);

                card1Explanation2Label.setFont(new java.awt.Font("SansSerif", 0, 14));
                card1Explanation2Label.setText("containing your application's");
                firstPanel.add(card1Explanation2Label);
                card1Explanation2Label.setBounds(230, 100, 198, 17);

                card1Explanation3Label.setFont(new java.awt.Font("SansSerif", 0, 14));
                card1Explanation3Label.setText("source files.");
                firstPanel.add(card1Explanation3Label);
                card1Explanation3Label.setBounds(230, 120, 82, 17);

                contentPanel.add(firstPanel, "card1");

                getContentPane().add(contentPanel);
                contentPanel.setBounds(0, 0, 750, 300);

                previousButton.setText("<< Previous");
                previousButton.addActionListener(new java.awt.event.ActionListener() {
                        public void actionPerformed(java.awt.event.ActionEvent evt) {
                                previousButtonActionPerformed(evt);
                        }
                });
                getContentPane().add(previousButton);
                previousButton.setBounds(150, 350, 100, 29);

                nextButton.setText("Next >>");
                nextButton.addActionListener(new java.awt.event.ActionListener() {
                        public void actionPerformed(java.awt.event.ActionEvent evt) {
                                try {
	                                nextButtonActionPerformed(evt);
                                } catch (CheckedAnalysisException e) {
	                                // TODO Auto-generated catch block
	                                e.printStackTrace();
                                } catch (IOException e) {
	                                // TODO Auto-generated catch block
	                                e.printStackTrace();
                                } catch (InterruptedException e) {
	                                // TODO Auto-generated catch block
	                                e.printStackTrace();
                                }
                        }
                });
                getContentPane().add(nextButton);
                nextButton.setBounds(250, 350, 100, 29);

                finshButton.setText("Finish");
                finshButton.addActionListener(new java.awt.event.ActionListener() {
                        public void actionPerformed(java.awt.event.ActionEvent evt) {
                                finshButtonActionPerformed(evt);
                        }
                });
                getContentPane().add(finshButton);
                finshButton.setBounds(350, 350, 100, 29);

                errorMessageLabel.setFont(new java.awt.Font("SansSerif", 1, 14)); // NOI18N
                errorMessageLabel.setForeground(new java.awt.Color(255, 0, 0));
                getContentPane().add(errorMessageLabel);
                errorMessageLabel.setBounds(0, 300, 500, 20);

                pack();
        }// </editor-fold>//GEN-END:initComponents

private void previousButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previousButtonActionPerformed
    if (step > MIN_STEP) {
        setStep(step - 1);
    }
    progressModel.removeAllElements();
	foundModel.removeAllElements();
}//GEN-LAST:event_previousButtonActionPerformed

private void nextButtonActionPerformed(java.awt.event.ActionEvent evt) throws CheckedAnalysisException, IOException, InterruptedException {//GEN-FIRST:event_nextButtonActionPerformed
	
	discover = new Thread(){
		@Override
        public void run(){
			IErrorLogger errorLogger = new IErrorLogger() {
				public void reportMissingClass(ClassNotFoundException ex) {
					String className = ClassNotFoundExceptionParser.getMissingClassName(ex);
					if (className != null) {
						logError("Missing class: " + className);
					} else {
						logError("Missing class: " + ex);
					}
				}
				public void reportMissingClass(ClassDescriptor classDescriptor) {
					logError("Missing class: " + classDescriptor.toDottedClassName());
				}
				public void logError(String message) {
					System.err.println("Error: " + message);
				}
				public void logError(String message, Throwable e) {
					logError(message + ": " + e.getMessage());
				}
				public void reportSkippedAnalysis(MethodDescriptor method) {
					logError("Skipped analysis of method " + method.toString());
				}
			};
			
			DiscoverSourceDirectories.Progress progress = new DiscoverSourceDirectories.Progress() {

				public void startRecursiveDirectorySearch() {
					progressModel.addElement("Scanning directories...");
				}
				public void doneRecursiveDirectorySearch() {
				}
				public void startScanningArchives(int numArchivesToScan) {
					progressModel.addElement("Scanning " + numArchivesToScan + " archives..");
				}
				public void doneScanningArchives() {
				}
				public void startScanningClasses(int numClassesToScan) {
					progressModel.addElement("Scanning " + numClassesToScan + " classes...");
				}
				public void finishClass() {
				}
				public void doneScanningClasses() {
				}
				public void finishArchive() {
				}
				public void startArchive(String name) {
                }
			};
			DiscoverSourceDirectories discoverSourceDirectories = new DiscoverSourceDirectories();
			discoverSourceDirectories.setProject(project);
			discoverSourceDirectories.setRootSourceDirectory(sourceRootBox.getText());
			discoverSourceDirectories.setErrorLogger(errorLogger);
			discoverSourceDirectories.setProgress(progress);

			try {
	            discoverSourceDirectories.execute();
            } catch (CheckedAnalysisException e1) {
	            // TODO Auto-generated catch block
	            e1.printStackTrace();
            } catch (IOException e1) {
	            // TODO Auto-generated catch block
	            e1.printStackTrace();
            } catch (InterruptedException e1) {
	            // TODO Auto-generated catch block
	            e1.printStackTrace();
            }
			
			jList1.setModel(foundModel);
			
			for (String srcDir : discoverSourceDirectories.getDiscoveredSourceDirectoryList()) {	
				foundModel.addElement(srcDir);
			}	
			
			if (step < MAX_STEP) {
			    setStep(step + 1);
			}
		}
	};
	discover.start();
}//GEN-LAST:event_nextButtonActionPerformed

private void finshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_finshButtonActionPerformed
	if(parentGUI != null)
	{
		parentGUI.setSourceDirecs(foundModel);
	}
	if(discover != null && discover.isAlive())
    	discover.stop();
	dispose();
}//GEN-LAST:event_finshButtonActionPerformed
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                final SourceDirectoryWizard dialog = new SourceDirectoryWizard(new javax.swing.JFrame(), true, new Project(), null);
                dialog.setVisible(true);
            }
        });
    }
    	private JFileChooser chooser;
    	private Project project;
    	private NewProjectWizard parentGUI;
    	private DefaultListModel foundModel;
    	private DefaultListModel progressModel;
    	private JList jList2;
    	public Thread discover;
        // Variables declaration - do not modify//GEN-BEGIN:variables
        private javax.swing.JButton browseButton;
        private javax.swing.JLabel card1Explanation1Label;
        private javax.swing.JLabel card1Explanation2Label;
        private javax.swing.JLabel card1Explanation3Label;
        private javax.swing.JLabel card1TitleLabel;
        private javax.swing.JPanel contentPanel;
        private javax.swing.JLabel errorMessageLabel;
        private javax.swing.JButton finshButton;
        private javax.swing.JPanel firstPanel;
        private javax.swing.JLabel jLabel1;
        private javax.swing.JLabel jLabel2;
        private javax.swing.JLabel jLabel3;
        private javax.swing.JList jList1;
        private javax.swing.JScrollPane jScrollPane1;
        private javax.swing.JScrollPane jScrollPane2;
        private javax.swing.JButton nextButton;
        private javax.swing.JButton previousButton;
        private javax.swing.JPanel secondPanel;
        private javax.swing.JTextField sourceRootBox;
        private javax.swing.JLabel sourceRootLabel;
        private javax.swing.JLabel srcFileIconLabel;
        // End of variables declaration//GEN-END:variables

    private int step;

    private void setStep(int step) {
        if (step < MIN_STEP || step > MAX_STEP) {
            throw new IllegalArgumentException("Invalid step " + step);
        }
        this.step = step;
        previousButton.setEnabled(step != MIN_STEP);
        nextButton.setEnabled(step != MAX_STEP && !sourceRootBox.getText().equals(""));

        CardLayout cards = (CardLayout) contentPanel.getLayout();
        cards.show(contentPanel, "card" + step);
        
    }
}
